package posti.test.swf.web.action;

import java.util.List;
import java.util.Map;

import ognl.DefaultMemberAccess;
import ognl.Ognl;
import ognl.OgnlException;

public class MappingHelper<S, T> {
	public interface MappingStrategy<S, T> {
		public void map(S source, T target, Map ctx);
	}

	protected class OgnlMappingStrategy implements MappingStrategy<S, T> {
		private Object sourceExpression;
		private Object targetExpression;

		public OgnlMappingStrategy(String source, String target) {
			try {
				this.sourceExpression = Ognl.parseExpression(source);
				this.targetExpression = Ognl.parseExpression(target);
			} catch (OgnlException e) {
				throw new RuntimeException(e);
			}
		}

		public void map(S source, T target, Map ctx) {
			try {
				Object value = Ognl.getValue(sourceExpression, ctx, source);
				Ognl.setValue(targetExpression, ctx, target, value);
			} catch (OgnlException e) {
				throw new RuntimeException(e);
			}
		}
	}

	private List<MappingStrategy> fieldMappings;
	private Map ctx;

	public MappingHelper() {
		ctx = this.createContext();
	}

	private Map createContext() {
		Map ctx = Ognl.createDefaultContext(null);
		Ognl.setMemberAccess(ctx, new DefaultMemberAccess(true));
		
		return ctx;
	}

	public void addToContext(String key, Object value) {
		this.ctx.put(key, value);
	}

	public void map(S source, T target) { 
		for (MappingStrategy<S,T> mapping : this.fieldMappings) {
			mapping.map(source, target, ctx);
		}
	}

	public void addMappingStrategy(MappingStrategy strategy) {
		this.fieldMappings.add(strategy);
	}

	public void addOgnlMapping(String sourceExpr, String targetExpr) {
		this.addMappingStrategy(new OgnlMappingStrategy(sourceExpr, targetExpr));
	}
}
